package com.itheima.service.impl;

import com.itheima.commons.pojo.CommonEntity;
import com.itheima.commons.thread.ResponseThreadLocal;
import com.itheima.commons.utils.SearchTools;
import com.itheima.service.AnalysisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.ResponseUtil;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.metrics.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.jupiter.params.shadow.com.univocity.parsers.annotations.Parsed;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @program: itheima-technology-platform
 * @description: 指标聚合分析实现
 * @author: zhanghz001
 * @create: 2021-05-18 21:17
 **/
@Service
@Slf4j
@RefreshScope
public class ZhzAnalysisServiceImpl implements AnalysisService {
    @Autowired
    private RestHighLevelClient client;
    
    /**
     * 获取搜索热词
     *
     * @param commonEntity
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, Long> hotwords(CommonEntity commonEntity) throws Exception {
        return null;
    }
    
    /**
     * 获取查询结果
     *
     * @param commonEntity
     * @return
     * @throws Exception
     */
    private SearchResponse getSearchResponse(CommonEntity commonEntity) throws Exception {
        //定义查询请求
        SearchRequest searchRequest = new SearchRequest();
        //指定去哪个索引查询
        searchRequest.indices(commonEntity.getIndexName());
        //构建资源查询构建器，主要用于拼接查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //将前端的dsl查询转化为XContentParser
        XContentParser parser = SearchTools.getXContentParser(commonEntity);
        //将parser解析成功查询API
        sourceBuilder.parseXContent(parser);
        //将sourceBuilder赋给searchRequest
        searchRequest.source(sourceBuilder);
        //执行查询
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        return response;
    }
    
    @Override
    public Map<Object, Object> metricAgg(CommonEntity commonEntity) throws Exception {
        //获取查询结果
        SearchResponse searchResponse = getSearchResponse(commonEntity);
        //对查询结果进行组装1
        Map<String, Aggregation> aggregationMap = searchResponse.getAggregations().asMap();
        HashMap<Object, Object> map = new HashMap<>();
        for (Map.Entry<String, Aggregation> entry : aggregationMap.entrySet()) {
            metricResultConverter(map, entry.getValue());
        }
        
        //对查询结果进行组装2 获取聚合对象是可以的 
        Aggregation aggregation = searchResponse.getAggregations().asList().get(0);
        //元数据是获取都为null
        // aggregation.getMetaData();
        // metricResultConverter(map, aggregation);
        
        //查询到的信息放到局部线程变量中        
        SearchTools.setResponseThreadLocal(searchResponse);
        //公共数据处理
        mbCommonConverter(map);
        
        //其他处理 
        return map;
    }
    
    private void mbCommonConverter(HashMap<Object, Object> map) {
        if (!CollectionUtils.isEmpty(ResponseThreadLocal.get())) {
            //    线程中获取数据
            map.put("list", ResponseThreadLocal.get());
            //清空数据,防止内存泄漏
            ResponseThreadLocal.clear();
        }
    }
    
    /**
     * 处理各种指标聚合的结果
     *
     * @param map
     * @param value
     */
    private void metricResultConverter(HashMap<Object, Object> map,
                                       Aggregation value) {
        String name = value.getClass().getName();
        switch (name) {
            case "org.elasticsearch.search.aggregations.metrics.ParsedAvg":
                double avg = ((ParsedAvg) value).getValue();
                map.put("value", avg);
                // ParsedAvg
                break;
            case "org.elasticsearch.search.aggregations.metrics.ParsedMax":
                double max = ((ParsedMax) value).getValue();
                map.put("value", max);
                // ParsedMax;
                break;
            case "org.elasticsearch.search.aggregations.metrics.ParsedMin":
                double min = ((ParsedMin) value).getValue();
                map.put("value", min);
                // ParsedMin;
                break;
            case "org.elasticsearch.search.aggregations.metrics.ParsedSum":
                double sum = ((ParsedSum) value).getValue();
                map.put("value", sum);
                // ParsedSum
                break;
            case "org.elasticsearch.search.aggregations.metrics.ParsedCardinality":
                //不重复的值
                double cardinality = ((ParsedCardinality) value).getValue();
                map.put("value", cardinality);
                // ParsedCardinality;
                break;
            case "org.elasticsearch.search.aggregations.metrics.ParsedStats":
                ParsedStats parsedStats = (ParsedStats) value;
                map.put("avg", parsedStats.getAvg());
                map.put("count", parsedStats.getCount());
                map.put("max", parsedStats.getMax());
                map.put("min", parsedStats.getMin());
                map.put("sum", parsedStats.getSum());
                // ParsedStats
                break;
            case "org.elasticsearch.search.aggregations.metrics.ParsedExtendedStats":
                //拓展状态统计
                
                ParsedExtendedStats parsedExtendedStats = (ParsedExtendedStats) value;
                map.put("avg", parsedExtendedStats.getAvg());
                map.put("count", parsedExtendedStats.getCount());
                map.put("max", parsedExtendedStats.getMax());
                map.put("min", parsedExtendedStats.getMin());
                map.put("sum", parsedExtendedStats.getSum());
                map.put("sum_of_squares", parsedExtendedStats.getSumOfSquares());
                map.put("variance", parsedExtendedStats.getVariance());
                map.put("std_deviation", parsedExtendedStats.getStdDeviation());
                map.put("lower", parsedExtendedStats.getStdDeviationBound(ExtendedStats.Bounds.LOWER));
                map.put("upper", parsedExtendedStats.getStdDeviationBound(ExtendedStats.Bounds.UPPER));
                // ParsedExtendedStats
                break;
            case "org.elasticsearch.search.aggregations.metrics.ParsedTDigestPercentiles":
                //百分位等级
                ParsedTDigestPercentiles parsedTDigestPercentiles = (ParsedTDigestPercentiles) value;
                for (Percentile percentile : parsedTDigestPercentiles) {
                    map.put(percentile.getValue(), percentile.getPercent());
                }
                // ParsedTDigestPercentiles
                break;
            case "org.elasticsearch.search.aggregations.metrics.ParsedTDigestPercentileRanks":
                // ParsedTDigestPercentileRanks
                //百分位度量
                ParsedTDigestPercentileRanks parsedTDigestPercentileRanks =
                        (ParsedTDigestPercentileRanks) value;
                for (Percentile percentile : parsedTDigestPercentileRanks) {
                    map.put(percentile.getValue(), percentile.getPercent());
                }
                break;
            default:
            
        }
    }
}
